package bosVM2.meta.Objects;

import java.util.HashMap;

import bosVM2.FaultHandling.*;
import bosVM2.meta.LookUp.Type;

public class BosMethod {

	private BosClass clss;
	private String methodName;
	private Type type;
	private HashMap<Integer,Object[]> ins;
	private Integer[] numArgs;
	private String[] args;
	
	//private Random rnd = new Random(10);
	//Faulthandling
	AnCodeFaultHandler an = AnCodeFaultHandler.getAnFaultHAndler();
	StringEncoderDecoder ham = new StringEncoderDecoder();

	/*
	 * Constructor
	 */
	public BosMethod(BosClass clss, String name, Type type, int numArgs, String[] args)
	{
		this.clss = clss;
		setName(name);
		this.type = type;
		this.numArgs = new Integer[2];
		setNumArgs(numArgs);
		encodeArgs(args);
	}
	/*
	 * Copy Constructor
	 */
	public BosMethod(BosMethod m)
	{
		this(m.getSuper(), m.getName(), m.getType(), m.getNumArgs(), m.getArgs());
		this.ins = new HashMap<Integer,Object[]>(m.getInstructions());
	}
	
	//Setters(An coded)
	private void setNumArgs(int na) {
		numArgs[0] = na;
		numArgs[1] = an.enCode(na);
	}
	
	/*
	 * Encode arguments
	 * @param args The arguments
	 */
	private void encodeArgs(String[] args) {
		this.args = new String[args.length];
		for(int i = 0; i < args.length; i++) {
			this.args[i] = ham.enCode(args[i]);
		}
	}
	
	public String[] getArgs() {
		String[] out = new String[args.length];
		for(int i = 0; i < args.length; i++) {
			Object[] temp = ham.deCode(args[i]);
			if((boolean) temp[0]) {
				out[i] = (String) temp[1];
				this.args[i] = ham.enCode((String) temp[1]);
			} else {
				out[i] = (String) temp[1];
			}
		}
		return out;
	}
	
	public String[] getArgsCoded() {
		return args;
	}
	
	private int getNumArgs()
	{
		if(!an.valid(numArgs[1]))
		{
			return numArgs[0];
		} 
		else 
		{
			return an.deCode(numArgs[1]);
		}
	}
		
	public BosClass getSuper()
	{
		return clss;
	}
	
	public void addInstructions(HashMap<Integer, Object[]> ins)
	{	
		this.ins = ins;
	}
	
	public String getName() {
		Object[] temp = ham.deCode(methodName);
		if((boolean) temp[0]) {
			methodName = ham.enCode(methodName);
		}
		return (String) temp[1];
	}
	
	public void setName(String s) {
		methodName = ham.enCode(s);
	}
	
	public Object[] instructionAt(int i)
	{
		return ins.get(i);
	}
	
	public void setInstructionAt(int i,Object[] o)
	{
		ins.put(i, o);
	}
	
	public HashMap<Integer,Object[]> getInstructions()
	{
		return getInstructionCopy();
	}

	
	
	public Type getType()
	{
		return type;
	}
	
	public void setArg(int index, String name)
	{
		args[index] = name;
	}
	
	public HashMap<Integer,Object[]> getInstructionCopy()
	{
		HashMap<Integer,Object[]> out = new HashMap<Integer,Object[]>();
		for(Integer i: ins.keySet())
		{
			Object[] newA = new Object[ins.get(i).length];
			for(int j = 0; j < newA.length; j++)
			{
				newA[j] = ins.get(i)[j];
			}
			out.put(i, newA);
		}
		return out;
	}
	
	//util
	public String toString() {
		return (String) ham.deCode(methodName)[1];
	}
	
	public void setNumArg(int i, int a)
	{
		if(a == 0)
		{
			numArgs[0] = i;
		}
		else if(a == 1)
		{
			numArgs[1] = i;
		}
	}
	
	public int getNumArg(int i)
	{
		if(i == 0)
		{
			return numArgs[0];
		}
		else
		{
			return numArgs[1];
		}
	}
	
	public String getNameI() {
		return methodName;
	}
	
	public void setNameI(String s) {
		methodName = s;
	}


}
